﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Microsoft.Office.Interop.Outlook;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Outlook.WorkItems.Extension.Manager.TeamProjectManager;
using Outlook.WorkItems.Extension.Controls;

namespace Outlook.WorkItems.Extension.Addin.Forms
{
    /// <summary>
    /// This form allow mapping definition between fields of workitem type and fields of mail message
    /// </summary>
    internal partial class DefineMappingForm : Form
    {
        /// <summary>
        /// Work Item Type
        /// </summary>
        private readonly WorkItemType _wiType;
        private readonly bool validateRequiredFields = true;

        /// <summary>
        /// Outlook Application
        /// </summary>
        private Microsoft.Office.Interop.Outlook.Application m_application;

        /// <summary>
        /// List of Mapping items
        /// </summary>
        public WorkItemMapping Mapping
        {
            get
            {
                return new WorkItemMapping() { MappingFields = bindingSource1.DataSource as List<MappingField>, WorkItemType = this._wiType.Name };
            }
        }

        /// <summary>
        /// Default constructor
        /// </summary>
        public DefineMappingForm()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="wiType">Work Item Type</param>
        /// <param name="app">Outlook Application</param>
        public DefineMappingForm(WorkItemType wiType, Microsoft.Office.Interop.Outlook.Application app, WorkItemMapping mapping)
            : this()
        {
            _wiType = wiType;
            m_application = app;
            List<MappingField> mappings = new List<MappingField>();

            if (mapping == null || mapping.MappingFields == null || mapping.MappingFields.Count == 0)
            {
                foreach (FieldDefinition item in _wiType.FieldDefinitions)
                {
                    if (item.IsEditable)
                    {
                        mappings.Add(new MappingField() { WiFieldName = item.Name });
                    }
                }
                mappings = mappings.OrderBy(mf => mf.WiFieldName).ToList();
                bindingSource1.DataSource = mappings;
            }
            else
            {
                bindingSource1.DataSource = mapping.MappingFields.OrderBy(mf => mf.WiFieldName).ToList();
            }

            MailItem mail = m_application.CreateItem(OlItemType.olMailItem) as MailItem;

            List<MailFieldItem> mailFields = new List<MailFieldItem>();
            mailFields.Add(new MailFieldItem());
            foreach (ItemProperty item in mail.ItemProperties)
            {
                mailFields.Add(new MailFieldItem() { ItemProperty = item });
            }
            mailFields = mailFields.OrderBy(mf => mf.Name).ToList();
            mailFieldItemBindingSource.DataSource = mailFields;
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="wiType">Work Item Type</param>
        /// <param name="app">Outlook Application</param>
        public DefineMappingForm(WorkItemType wiType, Microsoft.Office.Interop.Outlook.Application app, WorkItemMapping mapping, bool showStaticValues, bool validateRequiredFields)
            : this(wiType, app, mapping)
        {
            colStaticValue.Visible = showStaticValues;
            this.validateRequiredFields = validateRequiredFields;
            button1.Visible = showStaticValues;
        }

        /// <summary>
        /// Define static values : show Work Item Viewer
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            WorkItem wi = new WorkItem(_wiType);

            try
            {
                using (WorkItemForm frm = new WorkItemForm(_wiType.Store, wi))
                {
                    if (frm.ShowDialog() == DialogResult.OK)
                    {
                        foreach (var item in this.Mapping.MappingFields)
                        {
                            if (wi.Fields[item.WiFieldName].Value != null && !string.IsNullOrEmpty(wi.Fields[item.WiFieldName].Value.ToString()))
                            {
                                item.StaticValue = wi.Fields[item.WiFieldName].Value.ToString();
                            }
                        }
                        bindingSource1.ResetBindings(false);
                    }
                }
            }
            catch (System.Exception ex)
            {
                using (ErrorForm frm = new ErrorForm(ex))
                {
                    frm.ShowDialog();
                }
            }
        }

        private void DefineMappingForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (this.DialogResult == DialogResult.OK && this.validateRequiredFields)
            {
                WorkItemMapping mapping = this.Mapping;
                WorkItem wi = _wiType.NewWorkItem();
                foreach (MappingField mf in mapping.MappingFields)
                {
                    if (string.IsNullOrEmpty(mf.MessageFieldName) && string.IsNullOrEmpty(mf.StaticValue))
                    {
                        if (wi.Fields[mf.WiFieldName].IsRequired && wi.Fields[mf.WiFieldName].IsEditable)
                        {
                            e.Cancel = true;
                            MessageBox.Show(string.Format("Work Item Field {0} is required. Define mapping for this field.", mf.WiFieldName));
                            break;
                        }
                    }
                }
            }
        }
    }

    /// <summary>
    /// This type is used to display fields of mail item (ItemProperty) in a combobox
    /// </summary>
    internal class MailFieldItem
    {
        /// <summary>
        /// Field of mail message
        /// </summary>
        private ItemProperty m_itemProperty;

        /// <summary>
        /// Get or set mail field
        /// </summary>
        public ItemProperty ItemProperty
        {
            get { return m_itemProperty; }
            set { m_itemProperty = value; }
        }

        /// <summary>
        /// Get field name
        /// </summary>
        public string Name
        {
            get { return m_itemProperty != null ? m_itemProperty.Name : ""; }
        }
    }

    internal class WorkItemFieldItem
    {
        /// <summary>
        /// Field of mail message
        /// </summary>
        private FieldDefinition m_fieldDefinition;

        /// <summary>
        /// Get or set mail field
        /// </summary>
        public FieldDefinition FieldDefinition
        {
            get { return m_fieldDefinition; }
            set { m_fieldDefinition = value; }
        }

        /// <summary>
        /// Get field name
        /// </summary>
        public string Name
        {
            get { return m_fieldDefinition != null ? m_fieldDefinition.Name : ""; }
        }
    }
}
